#include <ConnectionBroker/client/TcpClient.h>
#include <ConnectionBroker/Packet.h>
#include <ConnectionBroker/ServerSettings.h>
#include <json/json.h>

#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/thread.hpp>

#include <set>

using namespace ConnectionBroker;

std::vector<std::string> gChannelNames;

void authCallback(TcpClientPtr pClient, const Packet& pMessage)
{
   std::cout << "auth gained" << std::endl;
   pClient->subscribeTo(gChannelNames);
   Packet p(8, pMessage.message());
   for(int i = 0; i < 10; ++i)
   {
      pClient->write(p);
   }
}

void testCallback(TcpClientPtr pClient, const Packet& pMessage)
{
   std::cout << "channel = " << pMessage.channel() << std::endl;
   std::cout << "message = " << pMessage.message() << std::endl;
   pClient->write(pMessage);
}

void channelsReceivedCallback(TcpClientPtr pClient, const std::vector<std::string>& channelNames)
{
   std::cout << "channels received" << std::endl;
   gChannelNames = channelNames;

   Json::Value authData(Json::objectValue);
   authData["encodedConnectionId"] = std::string("px2TxFlxS3ibHMR%2BW1uog%2FkB%2BDiMVsUZ7EGiUx0Pjopn833ECiDvJM56G%2Fe3mJ8SV3qh1B5zFPTRh6jmPHOu7g%3D%3D");
   pClient->sendAuthentication(authData);
}

int main()
{
   std::string address("localhost");
   ServerSettings settings(9014, address);
   boost::asio::io_service ioService;

   //Put the client set in a container so the shared pointers do not go out of scope.
   std::set<TcpClientPtr> pClients;

   //Create 1000 clients.
   for(int i = 0; i < 10; i++)
   {
      boost::shared_ptr<boost::asio::ssl::context> pContext(new boost::asio::ssl::context(boost::asio::ssl::context::sslv23));
      pContext->load_verify_file("ssl/server.crt");
      TcpClientPtr pClient(new TcpClient(ioService, settings, pContext));
      pClients.insert(pClient);
      pClient->setOnAuthenticationCallback(boost::bind(&authCallback, _1, _2));
      pClient->setOnMessageCallback(boost::bind(&testCallback, _1, _2));
      pClient->setOnChannelsReceivedCallback(boost::bind(&channelsReceivedCallback, _1, _2));

      //Start the server connection attemp.
      pClient->start();

      //Write a message (the message will get queued until the connection occurs).
      Json::Value val;
      val["message"] = "yo";
      Packet p(8, val);
      pClient->write(p);
   }

   //Start the service.
   boost::thread t(boost::bind(&boost::asio::io_service::run, &ioService));
   while(true)
      usleep(10000000);
   t.join();
}

